<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ElementPlus AST渲染引擎修复版</title>
    <link rel="stylesheet" href="my-vue-app/dist/index.css">
    <style>
        :root {
            --primary-color: #409EFF;
            --sidebar-bg: #304156;
            --sidebar-text: #bfcbd9;
            --sidebar-active: #409EFF;
            --header-height: 60px;
            --sidebar-width: 220px;
            --border-color: #DCDFE6;
            --bg-color: #f5f7fa;
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Microsoft YaHei", sans-serif;
        }
        
        body {
            background-color: var(--bg-color);
            color: #212529;
            height: 100vh;
            overflow: hidden;
        }
        
        #app {
            display: flex;
            flex-direction: column;
            height: 100vh;
        }
        
        .app-header {
            background-color: white;
            padding: 12px 20px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            display: flex;
            align-items: center;
            z-index: 100;
        }
        
        .header-title {
            display: flex;
            align-items: center;
            gap: 10px;
            font-weight: 700;
            font-size: 18px;
            color: #303133;
        }
        
        .header-title i {
            color: var(--primary-color);
        }
        
        .app-container {
            display: flex;
            flex: 1;
            overflow: hidden;
        }
        
        .editor-panel {
            width: 300px;
            background-color: white;
            border-right: 1px solid var(--border-color);
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }
        
        .panel-title {
            padding: 16px;
            font-size: 15px;
            font-weight: 600;
            color: #606266;
            border-bottom: 1px solid var(--border-color);
        }
        
        .json-editor {
            flex: 1;
            padding: 15px;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            line-height: 1.5;
            white-space: pre;
            border: none;
            outline: none;
            resize: none;
        }
        
        .preview-panel {
            flex: 1;
            padding: 20px;
            overflow: auto;
            background-color: var(--bg-color);
        }
        
        .preview-container {
            background-color: white;
            border-radius: 4px;
            box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
            min-height: calc(100vh - 140px);
            padding: 25px;
        }
        
        .empty-preview {
            text-align: center;
            padding: 40px;
            color: #909399;
        }
        
        .empty-preview i {
            font-size: 48px;
            margin-bottom: 15px;
            color: #dcdfe6;
        }
        
        .toolbar {
            padding: 15px;
            border-top: 1px solid var(--border-color);
            display: flex;
            gap: 10px;
        }
        
        .btn {
            padding: 8px 15px;
            border-radius: 4px;
            border: none;
            cursor: pointer;
            font-weight: 500;
            display: flex;
            align-items: center;
            gap: 6px;
            transition: all 0.2s;
        }
        
        .btn-primary {
            background-color: var(--primary-color);
            color: white;
        }
        
        .btn-outline {
            background-color: transparent;
            border: 1px solid var(--border-color);
            color: #606266;
        }
        
        .btn:hover {
            filter: brightness(0.95);
            transform: translateY(-1px);
        }
        
        .btn:active {
            transform: translateY(0);
        }
    </style>
</head>
<body>
    <div id="app">
        <header class="app-header">
            <div class="header-title">
                <i class="el-icon-s-operation"></i>
                <span>ElementPlus AST渲染引擎修复版</span>
            </div>
        </header>
        
        <div class="app-container">
            <div class="editor-panel">
                <div class="panel-title">AST编辑器</div>
                <textarea class="json-editor" id="ast-editor"></textarea>
                <div class="toolbar">
                    <button class="btn btn-primary" id="render-btn">
                        <i class="el-icon-refresh"></i> 渲染页面
                    </button>
                    <button class="btn btn-outline" id="reset-btn">
                        <i class="el-icon-delete"></i> 重置
                    </button>
                </div>
            </div>
            
            <div class="preview-panel">
                <div class="preview-container" id="preview-container">
                    <div class="empty-preview">
                        <i class="el-icon-picture"></i>
                        <p>编辑AST后点击"渲染页面"按钮查看效果</p>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- 引入Vue 3 -->
    <script src="my-vue-app/dist/vue.global.js"></script>
    <!-- 引入Element Plus -->
    <script src="my-vue-app/dist/index.full.js"></script>
     
    <script>
        // 默认AST示例
        const DEFAULT_AST = {
            "type": "el-container",
            "props": {
                "direction": "vertical",
                "style": {
                    "height": "100vh"
                }
            },
            "children": [
                {
                    "type": "div",
                    "props": {
                        "height": "60px"
                    },
                },{
                    type: 'el-row',
                    props: {
                        "gutter": 10
                        },
                        children: [{
                            type: 'el-col',
                            props: {
                                "span": 12
                                },
                        children: [{
                            type: 'el-input',
                            props: {
                                "placeholder": "请输入内容"
                                }
                        },{
                            type: 'el-button',
                             props: {
                                "type": "primary",
                                "icon": "el-icon-search",
                                "text":true,
                            }

                                
                        }]        
                        }]
                }
                ]
        };

        // 示例数据
        const SAMPLE_DATA = {
            users: [
                { name: '张三', email: 'zhangsan@example.com', phone: '13800138000' },
                { name: '李四', email: 'lisi@example.com', phone: '13900139000' },
                { name: '王五', email: 'wangwu@example.com', phone: '13700137000' }
            ]
        };

        // AST解析器 - 修复版
        class ASTParser {
            constructor() {
                // 组件映射表 - 修复el标签问题
                this.componentMap = {
                    // 布局组件
                    'Container': 'el-container',
                    'Header': 'el-header',
                    'Aside': 'el-aside',
                    'Main': 'el-main',
                    'Footer': 'el-footer',
                    
                    // 菜单组件
                    'Menu': 'el-menu',
                    'MenuItem': 'el-menu-item',
                    'SubMenu': 'el-submenu',
                    
                    // 数据展示
                    'Card': 'el-card',
                    'Table': 'el-table',
                    'TableColumn': 'el-table-column',
                    'Pagination': 'el-pagination',
                    
                    // 表单组件
                    'Button': 'el-button',
                    'Input': 'el-input',
                    'Select': 'el-select',
                    'Option': 'el-option',
                    'DatePicker': 'el-date-picker',
                    'Radio': 'el-radio',
                    'Checkbox': 'el-checkbox',
                    'Switch': 'el-switch',
                    'Slider': 'el-slider',
                    'TimePicker': 'el-time-picker',
                    'TimeSelect': 'el-time-select',
                    'Upload': 'el-upload',
                    'Rate': 'el-rate',
                    'ColorPicker': 'el-color-picker',
                    'Transfer': 'el-transfer',
                    'Form': 'el-form',
                    'FormItem': 'el-form-item',
                    'Cascader': 'el-cascader',
                    'InputNumber': 'el-input-number',
                    'Autocomplete': 'el-autocomplete',
                    
                    // 其他组件
                    'Alert': 'el-alert',
                    'Dialog': 'el-dialog',
                    'Drawer': 'el-drawer',
                    'Popover': 'el-popover',
                    'Tooltip': 'el-tooltip',
                    'Tag': 'el-tag',
                    'Badge': 'el-badge',
                    'Avatar': 'el-avatar',
                    'Progress': 'el-progress',
                    'Loading': 'el-loading',
                    'Message': 'el-message',
                    'Notification': 'el-notification',
                    'Tabs': 'el-tabs',
                    'TabPane': 'el-tab-pane',
                    'Steps': 'el-steps',
                    'Step': 'el-step',
                    'Timeline': 'el-timeline',
                    'TimelineItem': 'el-timeline-item',
                    'Collapse': 'el-collapse',
                    'CollapseItem': 'el-collapse-item',
                    'Carousel': 'el-carousel',
                    'CarouselItem': 'el-carousel-item',
                    'Calendar': 'el-calendar',
                    'Image': 'el-image',
                    'Skeleton': 'el-skeleton',
                    'Empty': 'el-empty',
                    'Backtop': 'el-backtop',
                    'Divider': 'el-divider',
                    'Link': 'el-link',
                    'Breadcrumb': 'el-breadcrumb',
                    'BreadcrumbItem': 'el-breadcrumb-item',
                    'Dropdown': 'el-dropdown',
                    'DropdownMenu': 'el-dropdown-menu',
                    'DropdownItem': 'el-dropdown-item',
                    'PageHeader': 'el-page-header',
                    'Tree': 'el-tree',
                    'TreeSelect': 'el-tree-select',
                    'Descriptions': 'el-descriptions',
                    'DescriptionsItem': 'el-descriptions-item',
                    'Result': 'el-result',
                    'Statistic': 'el-statistic',
                    'Affix': 'el-affix',
                    'Anchor': 'el-anchor',
                    'AnchorLink': 'el-anchor-link',
                    'InfiniteScroll': 'el-infinite-scroll',
                    'VirtualList': 'el-virtual-list',
                    'ConfigProvider': 'el-config-provider',
                    'Space': 'el-space',
                    'Scrollbar': 'el-scrollbar',
                    'CheckTag': 'el-check-tag',
                    'Watermark': 'el-watermark',
                    'Tour': 'el-tour',
                    'TourStep': 'el-tour-step'
                };
            }
            
            parse(node) {
                if (!node || !node.type) return null;
                
                // 修复el标签问题 - 使用映射表
                const componentType = this.componentMap[node.type] || node.type;
                
                const result = {
                    type: componentType,
                    props: node.props || {}
                };
                
                if (node.children) {
                    result.children = this.parseChildren(node.children);
                }
                
                return result;
            }
            
            parseChildren(children) {
                if (!children) return [];
                
                return children.map(child => {
                    if (typeof child === 'string') {
                        return child;
                    }
                    return this.parse(child);
                });
            }
        }

        // 渲染引擎 - 修复版
        class RenderEngine {
            constructor() {
                this.parser = new ASTParser();
                this.app = null;
                this.renderMode = 'dom'; // 默认使用DOM方式
            }
            
            // 方法1：直接DOM操作方式
            renderWithDOM(ast, container, data = {}) {
                // 清空容器
                container.innerHTML = '';
                
                // 解析AST并生成DOM元素
                const rootNode = this.parser.parse(ast);
                const element = this.createDOMElement(rootNode, data);
                
                // 附加到容器
                container.appendChild(element);
   
                    // 创建Vue应用并挂载
                    this.app = Vue.createApp({
                        data() {
                            return { pageData: data };
                        }
                    }).use(ElementPlus).mount(container);
                
            }
            
            // 创建DOM元素
            createDOMElement(node, data) {
                if (typeof node === 'string') {
                    return document.createTextNode(node);
                }
                
                const element = document.createElement(node.type);
                
                // 设置属性
                if (node.props) {
                    for (const [key, value] of Object.entries(node.props)) {
                        if (typeof value === 'string' && value.startsWith('$data.')) {
                            element.setAttribute(key, data[value.substring(6)]);
                        } else {
                            element.setAttribute(key, value);
                        }
                    }
                }
                
                // 处理子节点
                if (node.children) {
                    node.children.forEach(child => {
                        element.appendChild(this.createDOMElement(child, data));
                    });
                }
                
                return element;
            }
            
            // 方法2：模板动态渲染方式
            renderWithTemplate(ast, container, data = {}) {
                // 销毁之前的应用
                if (this.app) {
                    this.app.unmount();
                    container.innerHTML = '';
                }
                
                // 生成模板字符串
                const template = this.generateTemplate(ast);
                
                // 创建并挂载Vue应用
                this.app = Vue.createApp({
                    data() {
                        return { pageData: data };
                    },
                    template: template
                }).use(ElementPlus).mount(container);
            }
            
            // 生成Vue模板字符串
            generateTemplate(node) {
                if (typeof node === 'string') {
                    return node;
                }
                
                let template = `<${node.type}`;
                
                // 添加属性
                if (node.props) {
                    for (const [key, value] of Object.entries(node.props)) {
                        if (typeof value === 'string' && value.startsWith('$data.')) {
                            template += ` :${key}="pageData.${value.substring(6)}"`;
                        } else {
                            template += ` ${key}="${value}"`;
                        }
                    }
                }
                
                template += '>';
                
                // 处理子节点
                if (node.children) {
                    node.children.forEach(child => {
                        template += this.generateTemplate(child);
                    });
                }
                
                template += `</${node.type}>`;
                return template;
            }
            
            
            // 主渲染方法（默认使用DOM方式）
            render(ast, container, data = {}) {
                if (this.renderMode === 'dom') {
                    this.renderWithDOM(ast, container, data);
                } else {
                    this.renderWithTemplate(ast, container, data);
                }
                
            }
            
            // 设置渲染模式
            setRenderMode(mode) {
                this.renderMode = mode;
            }
        }



        // 页面初始化
        document.addEventListener('DOMContentLoaded', () => {
            const editor = document.getElementById('ast-editor');
            const renderBtn = document.getElementById('render-btn');
            const resetBtn = document.getElementById('reset-btn');
            const previewContainer = document.getElementById('preview-container');
            
            // 设置默认AST
            editor.value = JSON.stringify(DEFAULT_AST, null, 2);
            
            const renderEngine = new RenderEngine();
            
            // 渲染按钮点击事件
            renderBtn.addEventListener('click', () => {

                    try {
                        const ast = JSON.parse(editor.value);
                        renderEngine.render(ast, previewContainer, SAMPLE_DATA);
                    } catch (error) {
                        previewContainer.innerHTML = `
                            <div class="empty-preview">
                                <i class="el-icon-warning"></i>
                                <h3>渲染错误</h3>
                                <p>${error.message}</p>
                                <p>请检查AST语法是否正确</p>
                            </div>
                        `;
                        console.error('渲染错误:', error);
                    }
                
            });
            
            // 重置按钮点击事件
            resetBtn.addEventListener('click', () => {
                    editor.value = JSON.stringify(DEFAULT_AST, null, 2);
                    renderEngine.render(DEFAULT_AST, previewContainer, SAMPLE_DATA);
                });
            });
            
           
    </script>
</body>
</html>